package com.cc.springboot_test.config;

import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClusterConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Map;

@Configuration
public class RedisConfig {
    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    // 集群节点
    @Value("${redis_address}")
    private String clusterNodes;

    // 访问超时时间
    @Value("${redis_connect_timeout}")
    private Long timeout;

    // socket超时时间
    @Value("${redis_so_timeout:5000}")
    private Long soTimeout;

    // 最大直连数
    @Value("${redis_max_redirects}")
    private int maxRedirects;

    // 最大连接数
    @Value("${redis_max_active}")
    private int maxActive;

    // 最大空闲连接数
    @Value("${redis_max_idle}")
    private int maxIdle;

    // 最小空闲连接数
    @Value("${redis_min_idle}")
    private int minIdle;

    // 获取连接时的最大等待毫秒数（如果设置为阻塞时BlockWhenExhausted），如果超时就抛异常，小于零：阻塞不确定的时间，默认-1
    @Value("${redis_max_wait}")
    private int maxWaitMills;

    // redis权限认证
    @Value("${redis_auth}")
    private String redisAuth;

    // 逐出连接的最小空闲时间
    private int minEvictableIdleTimeMills = 300000;

    // 次逐出检查时，逐出的最大数目
    private int numTestsPerEvictionRun = 3;

    // 逐出扫描的时间间隔（毫秒）如果为负数，则不运行逐出线程，默认-1
    private int timeBetweenEvictionRunsMills = 60000;

    // 在获取连接时检查有效性
    private boolean testOnBorrow = true;

    // return pool时是否进行校验
    private boolean testOnReturn = true;

    // 在空闲时检查有效性
    private boolean testWhileIdle = true;

    @Bean
    public RedisClusterConfiguration getClusterConfiguration() {
        Map<String, Object> source = Maps.newLinkedHashMap();
        source.put("spring.redis.cluster.nodes", clusterNodes);
        source.put("spring.redis.cluster.timeout", timeout);
        source.put("spring.redis.cluster.max-redirects", maxRedirects);
        return new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
    }

    @Bean
    public JedisPoolConfig getJedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxActive);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMills);
        jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMills);
        jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMills);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setTestOnReturn(testOnReturn);
        jedisPoolConfig.setTestWhileIdle(testWhileIdle);
        return jedisPoolConfig;
    }

    @Bean
    public JedisConnectionFactory getConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(getClusterConfiguration());
        jedisConnectionFactory.setPoolConfig(getJedisPoolConfig());
        jedisConnectionFactory.setTimeout(soTimeout.intValue());
        if (StringUtils.isNoneEmpty(redisAuth)) {
            jedisConnectionFactory.setPassword(redisAuth);
        }
        return jedisConnectionFactory;
    }

    @Bean
    public JedisClusterConnection getJedisClusterConnection() {
        return (JedisClusterConnection) getConnectionFactory().getConnection();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> clusterTemplate = new RedisTemplate<>();
        // 使用String方式序列化，方便查问题
        clusterTemplate.setKeySerializer(clusterTemplate.getStringSerializer());
        clusterTemplate.setValueSerializer(clusterTemplate.getStringSerializer());
        clusterTemplate.setConnectionFactory(getConnectionFactory());
        return clusterTemplate;
    }
}
